﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EventApp
{
    /*事件（event)
    观察1: this.btnCreateChildForm.Click += new System.EventHandler(this.btnCreateChildForm_Click);
    观察2: public event EventHandler Click;
    观察3: public delegate void EventHandler(object sender, EventArgs e);
    1.事件的本质:事件的本质就是委托的进一步包装.
    延时思考: 买东西通常会有一个包装。(包装对实物起到保护作用)
    程序优秀: (健壮性) 代码规范、技术综合运用好(简化、好的技术点、项目的扩展性好...) ---> 不容易出问题.
    不容易出问题:容错能力。
    事件: 把委托用不到的"功能和用法"给你去掉.
    现实: 家庭版、专业版、企业版、服务器版

    2.事件
    【1】在委托类型前面添加event就可以定义事件
    【2】事件必须使用+=或-=，不能直接=赋值
    【3】事件移除不能使用null，只能使用-=的方式

    3.事件参与者
    【1】发送者(sender):也就是用来激发事件，通知所有的接收者接收消息
    private void btnSend_Click(object sender, EventArgs e)
        {
            EventChildReceive(this.txtSendMsg.Text);
        }

    【2】接收者(Receiver）:就是事件的处理者，在事件发送者触发事件后，自动执行的代码
    private void ReceiveMsg(string data)
    {
        this.txtContent.Text += data + "\r\n";
    }

    //事件和委托的对比
    第一、事件无法在"外面"赋值。比如"对象.事件=null",会出现编译错误，而委托可以
    好处：避免用户对事件直接操作，比如Click事件，如果允许Click=null,会把底层代码清除，事件可以起到
    保护作用。而委托相对"太开放".
    第二、event对象没有invoke()方法(了解）。

    5、委托和事件的选择
    第一、正常解决问题，你使用事件和委托没什么区别，但是，建议用委托
    第二、如果我们做控件二次开发，扩展控件的事件时，必须使用事件event
    */
    // 【1】声明委托
    public delegate void ReceiveDelete(string msg);
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            InitializeComponent();
        }

        //把子窗体对象放到容器中
        private List<Form> frmList = new List<Form>();

        private void btnCreateChildForm_Click(object sender, EventArgs e)
        {
            for (int i = 1; i < 4; i++) //创建3个子窗体
            {
                FrmChild frm = new FrmChild(i);
                frm.Show();
                //【4】关联委托变量和方法
                frm.EventChildReceive += ReceiveMsg;

                //将当前窗体对象添加到集合中去
                frmList.Add(frm);
            }
        }

        // 【2】事件的接收者
        private void ReceiveMsg(string data)
        {
            this.txtContent.Text += data + "\r\n";
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            foreach (FrmChild item in frmList)
            {
                //item.EventChildReceive = null; //这种方式不允许
                item.EventChildReceive -= ReceiveMsg; //只能通过这种方式移除事件
            }
        }
    }
}
